package com.edgar.plugin

import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.ApkVariant
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.internal.TaskContainerAdaptor
import com.android.build.gradle.internal.TaskFactory
import com.android.build.gradle.internal.pipeline.TransformTask
import com.edgar.plugin.hooks.BaseHooker
import com.edgar.plugin.hooks.ProcessResourceTaskHooker
import com.edgar.plugin.tasks.HookTask
import org.gradle.StartParameter
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.tasks.TaskState
import org.gradle.internal.reflect.Instantiator
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry

import javax.inject.Inject

public class ApkPlugin implements Plugin<Project>{

    private static final String TASK_NAME = "assembleHook"
    private Project project
    private String packageName
    private AppExtension android
    private Instantiator instantiator
    private boolean isBuildPlugin = false
    private TaskFactory taskFactory
    private Map<String,BaseHooker> hookers = new HashMap<>()

    private class ApkTaskListener implements TaskExecutionListener{

        @Override
        void beforeExecute(Task task) {
            if (task.project == project) {
                if (task in TransformTask) {
                    hookers[task.transform.name]?.beforeExecute(task)
                } else {
                    hookers[task.name]?.beforeExecute(task)
                }
            }
        }

        @Override
        void afterExecute(Task task, TaskState taskState) {
            if (task.project == project) {
                if (task in TransformTask) {
                    hookers[task.transform.name]?.afterExecute(task)
                } else {
                    if (task.name.equals("processDebugResources")){
                        ProcessResourceTaskHooker taskHooker =
                                new ProcessResourceTaskHooker(project,null)
                        taskHooker.setPackageName(packageName)
                        taskHooker.afterExecute(task)
                    }
//                    println "afterExecute task ${task.name}"
//                    BaseHooker taskHooker = hookers[task.name]
//                    println "TaskHooker ${hookers.size()} ${task.name}"
//                    taskHooker?.afterExecute(task)
                }
            }
        }
    }

    private def registerTaskHook(BaseHooker hooker){
        hooker.setPackageName(packageName)
        hookers.put(hooker.getTaskName(),hooker)
        println "register task hook ${hooker.getTaskName()}"
    }

    @Inject
    ApkPlugin(Instantiator instantiator, ToolingModelBuilderRegistry registry){
        this.instantiator = instantiator
    }

    @Override
    void apply(Project project) {
        this.project = project
        StartParameter startParameter = project.gradle.startParameter
        def taskNames = startParameter.taskNames
        taskNames.each {
            if (it.contains(TASK_NAME)){
                isBuildPlugin = true
            }
        }
        android = project.extensions.findByType(AppExtension)
        def defaultConfig = android.defaultConfig
        packageName = defaultConfig.applicationId
        println "applicationId:${packageName}"
        setupPlugin()
        setupTaskHook()
//        project.afterEvaluate {
//            android.applicationVariants.all{ ApplicationVariant variant ->
//            }
//            def processDebugResources = (ProcessAndroidResources)project.tasks['processDebugResources']
//            processDebugResources.outputs.upToDateWhen { false }
//            // 注入点
//            processDebugResources.doLast { ProcessAndroidResources i ->
//                println "inject point!"
//                hookAapt(i)
//            }
//        }
    }

    private void setupPlugin(){
        taskFactory = new TaskContainerAdaptor(project.tasks)
        project.afterEvaluate {
            android.applicationVariants.all { ApkVariant variant->
                if (variant.buildType.name.equalsIgnoreCase("debug")){
                    def variantName = "assemble${variant.name.capitalize()}Hook"
                    taskFactory.create(variantName,HookTask)
                    taskFactory.named(TASK_NAME,new Action<Task>() {
                        @Override
                        void execute(Task task) {
                            task.dependsOn(variantName)
                        }
                    })
                }
            }
        }
        project.task('assembleHook',dependsOn: 'assembleDebug',group:'build',description: 'Build plugin apk')
    }

    private void setupTaskHook(){
        if (!isBuildPlugin){
            return
        }
        project.gradle.addListener(new ApkTaskListener())
        project.afterEvaluate {
            android.applicationVariants.all { ApplicationVariant variant->
                    registerTaskHook(instantiator.newInstance(ProcessResourceTaskHooker,this.project,variant))
            }
        }
    }
}